package com.ctf.soft.ms.utils.jsonxml;

import com.thoughtworks.xstream.annotations.XStreamAlias;
import com.thoughtworks.xstream.core.util.QuickWriter;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
import com.thoughtworks.xstream.io.xml.PrettyPrintWriter;
import com.thoughtworks.xstream.io.xml.XppDriver;

import java.io.Writer;
import java.lang.reflect.Field;

/**
 * 
 * @author 朱雪霖
 * @date 2015年7月16日 上午9:08:18
 * @description 自定义driver，为有@XStreamData注解的属性添加<![CDATA[]]>标签
 */
public class CustomDriver extends XppDriver {

	@Override
	public HierarchicalStreamWriter createWriter(Writer out) {
		PrettyPrintWriter prettyPrintWriter = new PrettyPrintWriter(out) {
			boolean cdata = false;  
            Class<?> targetClass = null; 

            @Override
            public void startNode(String name, @SuppressWarnings("rawtypes") Class clazz) {
            	super.startNode(name, clazz);
            	//如果name为xml，则为类节点
            	if("xml".equals(name)){
                    targetClass = clazz;
            	}else if(!clazz.getSimpleName().equals(String.class.getSimpleName()) && !clazz.getSimpleName().equals(Long.class.getSimpleName())){
                    targetClass = clazz;
            	}else{
            		cdata = existsCdataOfSuperClass(targetClass, name, null);
            	}
            }
            
            @Override
            protected void writeText(QuickWriter writer, String text) {
            	if(cdata){
            		writer.write("<![CDATA["+text+"]]>");
            	}else{
            		super.writeText(writer, text);
            	}
            }
            
            /**
             * 
             * @description 判断是否有XStreamCdata注解
             * @author 朱雪霖
             * @date 2015年7月16日 上午9:24:52
             * @param clazz
             * @param fieldAlias
             * @return
             */
            private boolean existsCdata(Class<?> clazz, String fieldAlias){
            	//boolean hasCdata = false;
            	//获取类的所有属性
            	Field[] fields = clazz.getDeclaredFields();
            	//遍历类属性
            	for(Field field : fields){
            		//判断是否有@XStreamCDATA注解
            		if(field.getAnnotation(XStreamCDATA.class) !=null){
	            		//判断该属性是否有@XStreamAlias注解
	            		XStreamAlias alias = field.getAnnotation(XStreamAlias.class);
	            		if(alias == null){
	            			if(fieldAlias.equals(field.getName())){
	            				return true;
	            			}
	            		}else{
	            			if(fieldAlias.equals(alias.value())){
	            				return true;
	            			}
	            		}
            		}
            	}
            	return false;
            }
            
            /**
             * 
             * @description 循环查看父类属性是否有@XStreamCDATA注解
             * @author zhu
             * @date 2015年7月17日 上午10:20:43
             * @param clazz
             * @param fieldAlias
             * @return
             */
            private boolean existsCdataOfSuperClass(Class<?> clazz, String fieldAlias, Class<?> innerClass){
            	boolean flag = existsCdata(clazz, fieldAlias);
            	if(flag){
            		return flag;
            	}
            	if(innerClass != null){
            		flag = existsCdata(innerClass, fieldAlias);
            		return flag;
            	}
            	Class<?> superClazz = clazz.getSuperclass();
            	while(!superClazz.getSimpleName().equals(Object.class.getSimpleName())){
            		flag = existsCdata(superClazz, fieldAlias);
            		if(flag){
            			return flag;
            		}
            		superClazz = superClazz.getSuperclass();
            	}
            	return false;
            }
		};
		return prettyPrintWriter;
	}

}
